package com.liuwei.msmall.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liuwei.msmall.common.constant.ProductConstant;
import com.liuwei.msmall.common.dto.SkuFullReductionDTO;
import com.liuwei.msmall.common.dto.SkuStockTo;
import com.liuwei.msmall.common.dto.es.EsSkuModelDTO;
import com.liuwei.msmall.common.exception.RRException;
import com.liuwei.msmall.common.utils.PageUtils;
import com.liuwei.msmall.common.utils.Query;
import com.liuwei.msmall.common.utils.R;
import com.liuwei.msmall.product.dao.SpuInfoDao;
import com.liuwei.msmall.product.entity.*;
import com.liuwei.msmall.product.feign.EsFeginService;
import com.liuwei.msmall.product.feign.SkuFullReductionFeignService;
import com.liuwei.msmall.product.feign.WareFeignService;
import com.liuwei.msmall.product.service.*;
import com.liuwei.msmall.product.vo.SaleAttrVo;
import com.liuwei.msmall.product.vo.SkuImgVo;
import com.liuwei.msmall.product.vo.SkuInfoVo;
import com.liuwei.msmall.product.vo.SpuInfoVo;
import com.liuwei.msmall.product.vo.resp.SpuListVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("spuInfoService")
@Slf4j
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    SpuInfoDescService spuInfoDescService;
    @Resource
    SpuImagesService spuImagesService;

    @Resource
    ProductAttrValueService productAttrValueService;
    @Resource
    AttrService attrService;

   @Resource
   SkuImagesService skuImagesService;

    @Resource
    SkuInfoService skuInfoService;


    @Resource
    SkuSaleAttrValueService skuSaleAttrValueService;

    @Resource
    SkuFullReductionFeignService skuFullReductionFeignService;

    @Resource
    CategoryService categoryService;
    @Resource
    BrandService brandService;

    @Resource
    WareFeignService wareFeignService;

    @Resource
    EsFeginService esFeginService;



    @Override
    public PageUtils queryPage(Map<String, Object> params) {

        //取出搜索条件
        String status = (String) params.get("status");
        String key = (String) params.get("key");
        String brandIdStr = (String) params.get("brandId");
        String catelogStr = (String) params.get("catelogId");

        LambdaQueryWrapper<SpuInfoEntity> queryWrapper = new LambdaQueryWrapper<>();

        if (!StringUtils.isEmpty(status)){
            queryWrapper.eq(SpuInfoEntity::getPublishStatus,status);
        }
        if (StringUtils.isNotBlank(key)){
            queryWrapper.like(SpuInfoEntity::getSpuName,key).or().eq(SpuInfoEntity::getId,key);
        }

        if (StringUtils.isNotBlank(brandIdStr)&&!brandIdStr.equals("0")){
            queryWrapper.eq(SpuInfoEntity::getBrandId,brandIdStr);
        }
        if (StringUtils.isNotBlank(catelogStr)&&!catelogStr.equals("0")){
            queryWrapper.eq(SpuInfoEntity::getCatalogId,catelogStr);
        }


        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                queryWrapper
        );
        List<SpuInfoEntity> spuInfoEntities = page.getRecords();
        List<SpuListVo> spuInfoVos = spuInfoEntities.stream().map(item -> {
            SpuListVo spuInfoVo = new SpuListVo();
            BeanUtils.copyProperties(item, spuInfoVo);
            CategoryEntity categoryEntity = categoryService.getById(item.getCatalogId());
            spuInfoVo.setCategoryName(categoryEntity.getName());
            BrandEntity brandEntity = brandService.getById(item.getBrandId());
            spuInfoVo.setBrandName(brandEntity.getName());
            return spuInfoVo;
        }).collect(Collectors.toList());
        PageUtils pageUtils = new PageUtils(page);
        pageUtils.setList(spuInfoVos);
        return pageUtils;
    }

    /**
     * 使用分布式事务seata保证在设置商品满减信息时的数据一致性
     * @param spuInfoVo
     */
//    @GlobalTransactional(name = "saveSpuInfo",rollbackFor = Exception.class)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSpuInfo(SpuInfoVo spuInfoVo) {


        //保存对应的spu信息 pms_spu_info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();

        BeanUtils.copyProperties(spuInfoVo,spuInfoEntity);
        //设置创建时间，修改时间
        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());
        spuInfoEntity.setPublishStatus(ProductConstant.StatusEnum.STATUS_NEW.getCode());
        this.save(spuInfoEntity);


        //保存spu介绍图片信息 pms_spu_info_desc
        SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
        spuInfoDescEntity.setSpuId(spuInfoEntity.getId());
        //按逗号连接
        spuInfoDescEntity.setDecript(String.join(",",spuInfoVo.getDecript()));

        spuInfoDescService.save(spuInfoDescEntity);

        //保存spu基本描述图片信息 pms_spu_images
        List<String> images = spuInfoVo.getImages();
        List<SpuImagesEntity> spuImagesEntities = new ArrayList<>(spuInfoVo.getImages().size());
        images.forEach(imgUrl->{
            SpuImagesEntity spuImagesEntity = new SpuImagesEntity();
            spuImagesEntity.setImgUrl(imgUrl);
            spuImagesEntity.setSpuId(spuInfoEntity.getId());
            spuImagesEntities.add(spuImagesEntity);
        });
        spuImagesService.saveBatch(spuImagesEntities);

        //积分信息

        //spu对应的基本属性信息 pms_product_attr_value
        List<Long> attrIds = spuInfoVo.getBaseAttrs().stream().map(i -> i.getAttrId()).collect(Collectors.toList());
        Map<Long, AttrEntity> attrEntityMap = attrService.getAttrInfoMapByIds(attrIds);
        List<ProductAttrValueEntity> productAttrValueEntities = new ArrayList<>(spuInfoVo.getBaseAttrs().size());
        spuInfoVo.getBaseAttrs().stream().forEach(attr->{
            ProductAttrValueEntity entity = new ProductAttrValueEntity();
            AttrEntity attrEntity = attrEntityMap.get(attr.getAttrId());
            entity.setSpuId(spuInfoEntity.getId());
            entity.setAttrId(attr.getAttrId());
            entity.setAttrName(attrEntity.getAttrName());
            entity.setQuickShow(attr.getShowDesc());
            entity.setAttrValue(attr.getAttrValues());
            productAttrValueEntities.add(entity);
        });
        productAttrValueService.saveBatch(productAttrValueEntities);

        //保存每个sku信息

        List<SkuInfoVo> skus = spuInfoVo.getSkus();

        List<SkuFullReductionDTO> skuFullReductionDTOS = new ArrayList<>();
        skus.forEach(sku->{

            //sku基本信息  pms_sku_info
            SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
            BeanUtils.copyProperties(sku,skuInfoEntity);
            skuInfoEntity.setSpuId(spuInfoEntity.getId());
            skuInfoEntity.setBrandId(spuInfoVo.getBrandId());
            skuInfoEntity.setCatalogId(spuInfoVo.getCatalogId());
            skuInfoEntity.setSkuDefaultImg(getDefalutSkuImg(sku.getImages()));
            skuInfoService.save(skuInfoEntity);

            //sku销售属性信息  pms_sku_sale_attr_value
            List<SaleAttrVo> attr = sku.getAttr();
            if (!CollectionUtils.isEmpty(attr)){
                List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = attr.stream().map(saleAttr -> {
                    SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                    skuSaleAttrValueEntity.setAttrId(saleAttr.getAttrId());
                    skuSaleAttrValueEntity.setAttrValue(saleAttr.getAttrValue());
                    skuSaleAttrValueEntity.setSkuId(skuInfoEntity.getSkuId());
                    skuSaleAttrValueEntity.setAttrName(saleAttr.getAttrName());
                    return skuSaleAttrValueEntity;
                }).collect(Collectors.toList());
                skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);
            }

            //sku基本信息图片  pms_sku_images
            List<SkuImagesEntity> skuImagesEntities = sku.getImages().stream().filter(img-> !StringUtils.isBlank(img.getImgUrl()))
                    .map(skuImg -> {
                SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                skuImagesEntity.setDefaultImg(skuImg.getDefaultImg());
                skuImagesEntity.setSkuId(skuInfoEntity.getSkuId());
                skuImagesEntity.setImgUrl(skuImg.getImgUrl());
                return skuImagesEntity;
            }).collect(Collectors.toList());
            skuImagesService.saveBatch(skuImagesEntities);

            //sku对应的满减信息 msmall_mms数据库---》mms_sku_full_reduction
            //sku对应的会员价格信息 msmall_mms数据库 ---> mms_member_price
            SkuFullReductionDTO skuFullReductionDTO = new SkuFullReductionDTO();

            BeanUtils.copyProperties(sku,skuFullReductionDTO);
            skuFullReductionDTO.setSkuId(skuInfoEntity.getSkuId());
            skuFullReductionDTOS.add(skuFullReductionDTO);
        });

        /**
         * 调用远程服务批量保存商品优惠信息
         */
        R r = skuFullReductionFeignService.saveBatch(skuFullReductionDTOS);
        System.out.println("调用成功。。。");
        //模拟异常，测试分布式事务是否回滚
//        throw new RuntimeException("as");
    }

    @Override
    public void productUpBySpuId(Long spuId) {
        //通过spuid查出spu下的sku
        List<SkuInfoEntity> skuInfoEntities = skuInfoService.list(new QueryWrapper<SkuInfoEntity>().eq("spu_id", spuId));
        //拿到可检索的属性
        List<EsSkuModelDTO.Attr> attrs = getSearchAttrs(spuId);
        //查询每个sku库存信息
        Map<Long, Boolean> finalStockMap = getStockInfoMap(skuInfoEntities);
        //封装es sku模型
        List<EsSkuModelDTO> skuModels = bulidEsSkuModel(skuInfoEntities,attrs,finalStockMap);

        //调用检索服务将esSkuModels保存到es中
        saveToEs(skuModels,spuId);
    }

    @Override
    public void productDownBySpuId(Long spuId) {
        //1,修改商品状态
        this.baseMapper.updateStatus(spuId,ProductConstant.StatusEnum.STATUS_DOWN.getCode());
        //2，调用远程es服务下架商品
        esFeginService.deleteProduct(spuId);
    }

    /**
     * 从数据库删除商品
     * @param spuId
     */
    @Override
    public void productDelete(Long spuId) {

    }

    @Override
    public SpuInfoEntity getSpuInfoBySkuId(Long skuId) {
        SkuInfoEntity skuInfoEntity = skuInfoService.getById(skuId);
        SpuInfoEntity spuInfoEntity = this.baseMapper.selectById(skuInfoEntity.getSpuId());
        BrandEntity brandEntity = brandService.getById(spuInfoEntity.getBrandId());
        spuInfoEntity.setBrandName(brandEntity.getName());
        return spuInfoEntity;
    }

    private void saveToEs(List<EsSkuModelDTO> skuModels,Long spuId) {
            R r = esFeginService.savePoduct(skuModels);
            if(r.getCode()==0){
                //远程调用成功,更改商品状态为已上架,
                this.getBaseMapper().updateStatus(spuId, ProductConstant.StatusEnum.STATUS_UP.getCode());
            }else {
                //调用失败时
                /**
                 * feign的调用过程
                 *
                 * 1.封装要传输的数据（构造数据将对象转换成json）
                 *
                 * 2.发送请求执行，执行成功解码响应数据
                 *      exeAndDecode(templete)
                 * 3.远程调用失败时，默认有5次重试机制，也可以自定义
                 *     while(true){
                 *
                 *     }
                 */
                throw new RRException("调用远程es服务保存商品信息失败");
            }
    }

    private List<EsSkuModelDTO> bulidEsSkuModel(List<SkuInfoEntity> skuInfoEntities, List<EsSkuModelDTO.Attr> attrs, Map<Long, Boolean> finalStockMap) {

        List<EsSkuModelDTO> skuModels = skuInfoEntities.stream().map(item -> {
            EsSkuModelDTO esSkuModel = new EsSkuModelDTO();
            BeanUtils.copyProperties(item,esSkuModel);
            //赋值其他属性,skuPrice,skuImg,hasStock,hotScore,brandName,brandImg,catelogName,attrs(拿到该商品允许检索的属性)
            esSkuModel.setSkuPrice(item.getPrice());
            esSkuModel.setSkuImg(item.getSkuDefaultImg());
            //设置sku是否还有库存finalStockMap.get(item.getSkuId())
            esSkuModel.setHasStock(finalStockMap==null?false:finalStockMap.get(item.getSkuId()));
            //设置热度评分
            esSkuModel.setHotScore(0L);
            //设置品牌名称
            BrandEntity brandEntity = brandService.getById(item.getBrandId());
            esSkuModel.setBrandName(brandEntity.getName());
            esSkuModel.setBrandImg(brandEntity.getLogo());
            //设置分类名称
            CategoryEntity categoryEntity = categoryService.getById(item.getCatalogId());
            esSkuModel.setCatalogName(categoryEntity.getName());
            //设置sku的规格参数，由于一个spu下的规格参都是一样的，所以这里的sku就不用每个都去查询，直接在外面通过spuid查出
            esSkuModel.setAttrs(attrs);
            return esSkuModel;
        }).collect(Collectors.toList());
        return skuModels;
    }

    private Map<Long, Boolean> getStockInfoMap(List<SkuInfoEntity> skuInfoEntities) {

        //拿到skuids发送远程服务，统一查询出是否有库存
        // 调用库存系统查询该商品是否还有库存
        List<Long> skuids = skuInfoEntities.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
        Map<Long, Boolean> stockMap= null;
        R r = wareFeignService.getHasStock(skuids);
        TypeReference<List<SkuStockTo>> typeReference = new TypeReference<List<SkuStockTo>>() {};
        List<SkuStockTo> skuStocks = r.getData("data",typeReference);
        if (!CollectionUtils.isEmpty(skuStocks)){
            stockMap = skuStocks.stream().collect(Collectors.toMap(SkuStockTo::getSkuId, skuStockTo -> skuStockTo.getHasStock()));
        }else {
            throw new RRException("查询库存服务返回null:查询skuids "+JSON.toJSONString(skuids));
        }
        return stockMap;
    }

    private List<EsSkuModelDTO.Attr> getSearchAttrs(Long spuId) {
        //通过spuid查出可以进行检索的规格参数的attrids
        List<ProductAttrValueEntity> attrEntities= productAttrValueService.getSearchAttrBySpuId(spuId);
        List<EsSkuModelDTO.Attr> attrs = attrEntities.stream().map(item -> {
            EsSkuModelDTO.Attr attr = new EsSkuModelDTO.Attr();
            BeanUtils.copyProperties(item, attr);
            //设置属性值
            attr.setAttrValue(item.getAttrValue());
            return attr;
        }).collect(Collectors.toList());
        return attrs;
    }

    private String getDefalutSkuImg(List<SkuImgVo> images) {

        for (SkuImgVo image : images) {
            if (image.getDefaultImg() == 1){
                return image.getImgUrl();
            }

        }
        return null;
    }

}
